package org.redis.cluster.command;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.redis.cluster.RedisCluster;
import org.redis.cluster.command.info.InfoFieldProvider;
import org.redis.cluster.extension.ExtensionLoader;
import org.redis.cluster.plugin.Plugin;
import org.redis.cluster.processor.CommandProcessor;
import org.redis.cluster.redis.RedisCommand;
import org.redis.cluster.redis.transport.RedisReply;
import org.redis.cluster.redis.transport.reply.RedisBulkReply;
import org.redis.cluster.transport.session.Session;

public class InfoCommandProcessor implements CommandProcessor,Plugin {
	
	private final static String COMMAND="INFO";
	
	private final static String SHOW_ALL_PARAM[]={"ALL","DEFAULT"};
	
	private final static String GROUP_START="# ";
	
	private final static String FIELD_VALUE_CONNECTOR=":";
	
	private final static String LINE_END="\r\n";
	
	private Map<String,InfoFieldProvider> fieldProviders;
	
	private ExtensionLoader extensionLoader;
	
	@Override
	public void init(RedisCluster redisCluster) {
		this.extensionLoader=redisCluster.getExtensionLoader();
		this.fieldProviders=initFieldProviders();
	}
	
	@Override
	public void destroy() {
	}

	@Override
	public RedisReply process(RedisCommand command, Session session) {
		if(MapUtils.isEmpty(fieldProviders)) {
			return null;
		}
		
		String group=(command.getParameterCount()==2?new String(command.getParameters()[1]):"").toUpperCase();
		StringBuilder info;
		
		if(StringUtils.isBlank(group) || ArrayUtils.contains(SHOW_ALL_PARAM, group)) {
			info=getInfo();
		}
		else {
			info=getInfo(group);
		}
		
		if(info==null) {
			return null;
		}
		
		return new RedisBulkReply(info.toString());
	}

	@Override
	public String getSupportCommand() {
		return COMMAND;
	}
	
	protected StringBuilder getInfo() {
		if(MapUtils.isEmpty(fieldProviders)) {
			return null;
		}
		
		StringBuilder info=new StringBuilder();
		for(String group:fieldProviders.keySet()) {
			StringBuilder groupInfo=getInfo(group);
			if(groupInfo==null) {
				continue;
			}
			
			info.append(groupInfo);
			info.append(LINE_END);
		}
		
		return info;
	}
	
	protected StringBuilder getInfo(String group) {
		InfoFieldProvider provider=fieldProviders.get(group);
		if(provider==null) {
			return null;
		}
		
		StringBuilder info=new StringBuilder();
		info.append(GROUP_START);
		info.append(StringUtils.capitalize(provider.getGroup()));
		info.append(LINE_END);
		
		for(Entry<String,Object> field:provider.getFields().entrySet()) {
			info.append(field.getKey());
			info.append(FIELD_VALUE_CONNECTOR);
			info.append(field.getValue());
			info.append(LINE_END);
		}

		return info;
	}
	
	protected Map<String,InfoFieldProvider> initFieldProviders() {
		Collection<InfoFieldProvider> providers=extensionLoader.load(InfoFieldProvider.class);
		if(CollectionUtils.isEmpty(providers)) {
			return MapUtils.EMPTY_MAP;
		}
		
		Map<String,InfoFieldProvider> result=new HashMap<String,InfoFieldProvider>();
		for(InfoFieldProvider provider:providers) {
			result.put(provider.getGroup().toUpperCase(), provider);
		}
		
		return result;
	}
}